// Copyright (C) 2025, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use quiche::ConnectionId;

use crate::QuicResult;

/// A customizable generator to derive and verify QUIC connection IDs.
///
/// For QUIC servers, it can be useful to encode additional information in the
/// source connection ID. This trait allows users to implement their own logic
/// for that purpose. The crate also provides [`SimpleConnectionIdGenerator`]
/// if no such customization is needed.
///
/// Clients currently can't configure a [`ConnectionIdGenerator`] and always use
/// the [`SimpleConnectionIdGenerator`].
pub trait ConnectionIdGenerator<'a>: Send + 'static {
    /// Creates a new [`ConnectionId`] according to the generator's logic.
    ///
    /// The `socket_cookie` is propagated unchanged from the
    /// [`QuicListener`](crate::socket::QuicListener) that received the
    /// connection.
    fn new_connection_id(&self, socket_cookie: u64) -> ConnectionId<'a>;

    /// Verifies whether `cid` was generated by this [`ConnectionIdGenerator`].
    ///
    /// `socket_cookie` matches the value that would have been passed to
    /// `new_connection_id` calls. The method should return an [`Err`] variant
    /// if the connection ID can't be verified.
    fn verify_connection_id(
        &self, socket_cookie: u64, cid: &ConnectionId,
    ) -> QuicResult<()>;
}

/// A [`ConnectionIdGenerator`] which creates random 20-byte connection IDs.
///
/// Random bytes are pulled directly from the operating system to create an ID.
/// Any `socket_cookie` value is ignored.
#[derive(Debug, Clone, Default)]
pub struct SimpleConnectionIdGenerator;

impl ConnectionIdGenerator<'static> for SimpleConnectionIdGenerator {
    fn new_connection_id(&self, _socket_cookie: u64) -> ConnectionId<'static> {
        let mut buf = vec![0; 20];
        boring::rand::rand_bytes(&mut buf).unwrap();

        ConnectionId::from_vec(buf)
    }

    /// Performs no verification, because this generator can create
    /// any valid connection ID.
    fn verify_connection_id(
        &self, _socket_cookie: u64, _cid: &ConnectionId<'_>,
    ) -> QuicResult<()> {
        Ok(())
    }
}
